#include "ast_node.h"
#include <stdlib.h>
#include <stdio.h>
#include "y.tab.h"
#include "symtable.h"

// Create node with given token and value - no children
struct ast_node *ast_create(int token, int value) {

	struct ast_node *new_node = malloc(sizeof(struct ast_node));
	new_node->token = token;
	new_node->value = value;
	dd_da_init(&new_node->children, sizeof(struct ast_node));
	return new_node;

}

void ast_child_add(struct ast_node *parent, struct ast_node *child) {
	dd_da_add(&parent->children, child);
}

void ast_delete(struct ast_node *node) {

	// Delete children
	for (int i = 0; i < node->children.elements; i++) {
		struct ast_node *child = dd_da_get(&node->children, i);
		ast_delete(child);
	}

	dd_da_free(&node->children);
	free(node);
}

// Print whole node tree, meant for debugging only
int tabs = 0;
void ast_print(struct ast_node *node) {

	// Print tabs (if any)
	for (int i = 0; i < tabs; i++) {
		printf("\t");
	}

	if (tabs == 0) {
		printf("Abstract Syntax Tree:\n");
		printf("*** ");
	}
	else {
		printf("* ");
	}

	// Print actual node
	char *type;
	switch (node->token) {

		case GAME:
			printf("GAME");
			break;
		case WORLD:
			printf("WORLD: %s", symtable[node->value].lexptr);
			break;
		case STRUCT:
			printf("STRUCT: %s", symtable[node->value].lexptr);
			break;

		// Expression symbols
		case NUMBER:
			printf("NUMBER: %d", node->value);
			break;
		case '+':
			printf("ADDITION");
			break;
		case '-':
			printf("SUBSTRACTION");
			break;
		case '*':
			printf("MULTIPLICATION");
			break;
		case '/':
			printf("DIVISION");
			break;
		case '=':
			printf("ASSIGNMENT");
			break;
		case ID:
			printf("IDENTIFIER: %s", symtable[node->value].lexptr);
			break;
		case FUNCTION_DECLARATION:
			printf("FUNCTION DECLARATION: %s", symtable[node->value].lexptr);
			break;
		case NODE:
			printf("NODE");
			break;
		case FUNCTION_CALL:
			printf("FUNCTION CALL");
			break;

		case DEFINE:
			type = "unrecognised";
			switch (symtable[node->value].token) {
				case INTEGER:
					type = "int";
					break;
				case FLOAT:
					type = "float";
					break;
				case STRING:
					type = "string";
					break;
				case STRUCT:
					type = "struct";
					break;
				case UNDEFINED:
					type = "undefined";
					break;
				default:
					break;
			}
			printf("DEFINITION: (%s) %s",
				type,
				symtable[node->value].lexptr
			);
			break;

		default:
			printf("%d | %d", node->token, node->value);
			break;
	}

	printf("\n");

	// Print children
	tabs++;
	for (int i = 0; i < node->children.elements; i++) {
		struct ast_node *child = dd_da_get(&node->children, i);
		ast_print(child);
	}
	tabs--;
}
